"""
Visual effects system for tank battle game
"""
import pygame
import random
import math
from typing import List, Tuple, Optional


class Particle:
    """Single particle for particle effects"""
    
    def __init__(self, x: float, y: float, vx: float, vy: float, 
                 color: Tuple[int, int, int], size: float, lifetime: float):
        """
        Initialize particle
        
        Args:
            x, y: Position
            vx, vy: Velocity
            color: RGB color tuple
            size: Particle size
            lifetime: Lifetime in seconds
        """
        self.x = x
        self.y = y
        self.vx = vx
        self.vy = vy
        self.color = color
        self.size = size
        self.lifetime = lifetime
        self.max_lifetime = lifetime
        self.alive = True
    
    def update(self, dt: float):
        """Update particle"""
        # Update position
        self.x += self.vx * dt
        self.y += self.vy * dt
        
        # Apply gravity
        self.vy += 200 * dt
        
        # Apply friction
        self.vx *= 0.98
        self.vy *= 0.98
        
        # Update lifetime
        self.lifetime -= dt
        if self.lifetime <= 0:
            self.alive = False
    
    def render(self, screen: pygame.Surface):
        """Render particle"""
        if not self.alive:
            return
        
        # Calculate alpha based on lifetime
        alpha = int(255 * (self.lifetime / self.max_lifetime))
        alpha = max(0, min(255, alpha))
        
        # Create surface with alpha
        size = int(self.size * (self.lifetime / self.max_lifetime))
        if size <= 0:
            return
        
        surf = pygame.Surface((size * 2, size * 2), pygame.SRCALPHA)
        color_with_alpha = (*self.color, alpha)
        pygame.draw.circle(surf, color_with_alpha, (size, size), size)
        
        screen.blit(surf, (int(self.x - size), int(self.y - size)))


class ParticleEmitter:
    """Particle emitter for creating particle effects"""
    
    def __init__(self, x: float, y: float):
        """Initialize particle emitter"""
        self.x = x
        self.y = y
        self.particles: List[Particle] = []
        self.active = True
    
    def emit_explosion(self, num_particles: int = 30, colors: Optional[List[Tuple[int, int, int]]] = None):
        """
        Create explosion effect
        
        Args:
            num_particles: Number of particles to emit
            colors: List of colors to use
        """
        if colors is None:
            colors = [(255, 200, 0), (255, 100, 0), (255, 50, 0), (150, 150, 150)]
        
        for _ in range(num_particles):
            # Random angle and speed
            angle = random.uniform(0, 2 * math.pi)
            speed = random.uniform(50, 200)
            
            vx = math.cos(angle) * speed
            vy = math.sin(angle) * speed
            
            color = random.choice(colors)
            size = random.uniform(2, 6)
            lifetime = random.uniform(0.5, 1.5)
            
            particle = Particle(self.x, self.y, vx, vy, color, size, lifetime)
            self.particles.append(particle)
    
    def emit_smoke(self, num_particles: int = 10):
        """Create smoke effect"""
        colors = [(100, 100, 100), (80, 80, 80), (60, 60, 60)]
        
        for _ in range(num_particles):
            vx = random.uniform(-20, 20)
            vy = random.uniform(-50, -20)
            
            color = random.choice(colors)
            size = random.uniform(3, 8)
            lifetime = random.uniform(1.0, 2.0)
            
            particle = Particle(self.x, self.y, vx, vy, color, size, lifetime)
            self.particles.append(particle)
    
    def emit_sparks(self, num_particles: int = 20):
        """Create spark effect"""
        colors = [(255, 255, 100), (255, 255, 200), (255, 200, 100)]
        
        for _ in range(num_particles):
            angle = random.uniform(0, 2 * math.pi)
            speed = random.uniform(100, 300)
            
            vx = math.cos(angle) * speed
            vy = math.sin(angle) * speed
            
            color = random.choice(colors)
            size = random.uniform(1, 3)
            lifetime = random.uniform(0.2, 0.6)
            
            particle = Particle(self.x, self.y, vx, vy, color, size, lifetime)
            self.particles.append(particle)
    
    def emit_debris(self, num_particles: int = 15):
        """Create debris effect"""
        colors = [(100, 80, 60), (80, 60, 40), (120, 100, 80)]
        
        for _ in range(num_particles):
            angle = random.uniform(0, 2 * math.pi)
            speed = random.uniform(80, 150)
            
            vx = math.cos(angle) * speed
            vy = math.sin(angle) * speed - 50  # Upward bias
            
            color = random.choice(colors)
            size = random.uniform(2, 5)
            lifetime = random.uniform(0.8, 1.5)
            
            particle = Particle(self.x, self.y, vx, vy, color, size, lifetime)
            self.particles.append(particle)
    
    def update(self, dt: float):
        """Update all particles"""
        # Update particles
        for particle in self.particles:
            particle.update(dt)
        
        # Remove dead particles
        self.particles = [p for p in self.particles if p.alive]
        
        # Deactivate if no particles left
        if not self.particles:
            self.active = False
    
    def render(self, screen: pygame.Surface):
        """Render all particles"""
        for particle in self.particles:
            particle.render(screen)
    
    def is_active(self) -> bool:
        """Check if emitter is still active"""
        return self.active and len(self.particles) > 0


class ExplosionAnimation:
    """Explosion animation using expanding circles"""
    
    def __init__(self, x: float, y: float, max_radius: float = 40):
        """
        Initialize explosion animation
        
        Args:
            x, y: Center position
            max_radius: Maximum radius of explosion
        """
        self.x = x
        self.y = y
        self.max_radius = max_radius
        self.current_radius = 0
        self.lifetime = 0.5  # seconds
        self.max_lifetime = self.lifetime
        self.active = True
        
        # Multiple expanding rings
        self.rings = [
            {'radius': 0, 'color': (255, 200, 0), 'speed': 100},
            {'radius': 0, 'color': (255, 100, 0), 'speed': 80},
            {'radius': 0, 'color': (255, 50, 0), 'speed': 60}
        ]
    
    def update(self, dt: float):
        """Update explosion animation"""
        self.lifetime -= dt
        
        if self.lifetime <= 0:
            self.active = False
            return
        
        # Update rings
        for ring in self.rings:
            ring['radius'] += ring['speed'] * dt
    
    def render(self, screen: pygame.Surface):
        """Render explosion animation"""
        if not self.active:
            return
        
        # Calculate alpha based on lifetime
        alpha = int(255 * (self.lifetime / self.max_lifetime))
        
        # Draw rings from largest to smallest
        for ring in reversed(self.rings):
            if ring['radius'] > 0 and ring['radius'] <= self.max_radius:
                # Create surface for ring
                size = int(ring['radius']) * 2 + 4
                surf = pygame.Surface((size, size), pygame.SRCALPHA)
                
                color_with_alpha = (*ring['color'], alpha)
                pygame.draw.circle(surf, color_with_alpha, 
                                 (size // 2, size // 2), 
                                 int(ring['radius']), 3)
                
                screen.blit(surf, (int(self.x - ring['radius'] - 2), 
                                  int(self.y - ring['radius'] - 2)))
    
    def is_active(self) -> bool:
        """Check if animation is still active"""
        return self.active


class EffectsManager:
    """Manager for all visual effects"""
    
    def __init__(self):
        """Initialize effects manager"""
        self.particle_emitters: List[ParticleEmitter] = []
        self.explosions: List[ExplosionAnimation] = []
    
    def create_explosion(self, x: float, y: float, size: str = "normal"):
        """
        Create explosion effect
        
        Args:
            x, y: Position
            size: Size of explosion ("small", "normal", "large")
        """
        # Create explosion animation
        radius_map = {
            "small": 20,
            "normal": 40,
            "large": 60
        }
        explosion = ExplosionAnimation(x, y, radius_map.get(size, 40))
        self.explosions.append(explosion)
        
        # Create particle emitter
        emitter = ParticleEmitter(x, y)
        
        particle_count_map = {
            "small": 15,
            "normal": 30,
            "large": 50
        }
        
        emitter.emit_explosion(particle_count_map.get(size, 30))
        emitter.emit_smoke(10 if size == "small" else 15 if size == "normal" else 20)
        emitter.emit_debris(8 if size == "small" else 15 if size == "normal" else 25)
        
        self.particle_emitters.append(emitter)
    
    def create_bullet_impact(self, x: float, y: float):
        """Create bullet impact effect"""
        emitter = ParticleEmitter(x, y)
        emitter.emit_sparks(15)
        self.particle_emitters.append(emitter)
    
    def create_tank_dust(self, x: float, y: float):
        """Create dust effect for moving tank"""
        emitter = ParticleEmitter(x, y)
        
        # Small dust particles
        colors = [(150, 130, 100), (130, 110, 80)]
        for _ in range(3):
            vx = random.uniform(-10, 10)
            vy = random.uniform(-10, 5)
            color = random.choice(colors)
            size = random.uniform(1, 3)
            lifetime = random.uniform(0.3, 0.8)
            
            particle = Particle(x, y, vx, vy, color, size, lifetime)
            emitter.particles.append(particle)
        
        self.particle_emitters.append(emitter)
    
    def update(self, dt: float):
        """Update all effects"""
        # Update particle emitters
        for emitter in self.particle_emitters:
            emitter.update(dt)
        
        # Remove inactive emitters
        self.particle_emitters = [e for e in self.particle_emitters if e.is_active()]
        
        # Update explosions
        for explosion in self.explosions:
            explosion.update(dt)
        
        # Remove inactive explosions
        self.explosions = [e for e in self.explosions if e.is_active()]
    
    def render(self, screen: pygame.Surface):
        """Render all effects"""
        # Render explosions
        for explosion in self.explosions:
            explosion.render(screen)
        
        # Render particle emitters
        for emitter in self.particle_emitters:
            emitter.render(screen)
    
    def clear_all(self):
        """Clear all effects"""
        self.particle_emitters.clear()
        self.explosions.clear()


# Singleton instance
_effects_manager_instance: Optional[EffectsManager] = None


def get_effects_manager() -> EffectsManager:
    """Get singleton effects manager instance"""
    global _effects_manager_instance
    
    if _effects_manager_instance is None:
        _effects_manager_instance = EffectsManager()
    
    return _effects_manager_instance
